"""

minor flickering is ok, as long as it's fast

"""

from __future__ import division, with_statement

from tools import *

from scipy.misc import imshow

class Viewer(object):

    instances = []
    key_events = dict()

    def __init__(self, name="", show_fps=False):
        self.image = None

        self.show_fps = show_fps
        self.clock = pyglet.clock.Clock()
        self.fps_display = pyglet.clock.ClockDisplay(clock=self.clock)

        #XXX use double buffering?
        self.window = pyglet.window.Window()
        #~ self.window = pyglet.window.Window(vsync=False) #XXX faster
        self.window.set_caption(name)
        self.window.clear()

        self.key_events = dict()
        self.last_key_pressed = None

        # set up event handler
        def on_key_press(symbol, modifiers):
            self.last_key_pressed = symbol

            # local callbacks
            callback = self.key_events.get(symbol)
            if callback is not None:
                callback()
            else: # try global
                callback = Viewer.key_events.get(symbol)
                if callback is not None:
                    callback()
        self.window.on_key_press = on_key_press

        # close events
        self.window.on_close = self.close
        self.set_callback(pyglet.window.key.ESCAPE, self.close)

        # bounding box selection events
        self.selecting_bbox = None
        def on_mouse_press(x, y, button, modifiers):
            y = self.window.height - y
            #~ self.selecting_bbox = Bbox([(x,y), (x,y)])
            self.selecting_bbox = Bbox([(y,x), (y,x)])
        def on_mouse_release(x, y, button, modifiers):
            y = self.window.height - y
            #~ self.bbox = Bbox([self.selecting_bbox.top_left, (x,y)])
            self.bbox = Bbox([self.selecting_bbox.top_left, (y,x)])
            print self.bbox.points
        def on_mouse_drag(x, y, dx, dy, buttons, modifiers):
            y = self.window.height - y
            #~ self.selecting_bbox = Bbox([self.selecting_bbox.top_left, (x,y)])
            self.selecting_bbox = Bbox([self.selecting_bbox.top_left, (y,x)])
            image = pyglet2numpy(self.image)
            self.selecting_bbox.draw(image)
            self.update_image(image)
        self.window.on_mouse_press = on_mouse_press
        self.window.on_mouse_release = on_mouse_release
        self.window.on_mouse_drag = on_mouse_drag

        self.alive = True

        Viewer.instances.append(self)
        pyglet.gl.glScalef(1, -1, 1)

    def close(self):
        self.alive = False

    def update_image(self, image, copy=True, draw=False):
        if image is None: # happens at end of video stream
            return
        copied = False

        if isinstance(image, ndarray):
            image = numpy2pyglet(image, copy=copy)
            copied = copied or copy

        if copy and not copied:
            #~ self.image = image.copy() #XXX
            self.image = image
            copied = True
        else:
            self.image = image

        if draw:
            self._on_draw()

    def _on_draw(self):
        self.window.switch_to()
        self.clock.tick()
        self.window.dispatch_events()

        if self.image is None:
            self.window.clear()
        else:
            self.window.width, self.window.height = self.image.width, self.image.height
            self.image.blit(0, -self.image.height)

        if self.show_fps:
            #~ pyglet.gl.glScalef(1, 1, 1)
            self.fps_display.draw()
            #~ pyglet.gl.glScalef(1, -1, 1)

        self.window.flip()

    def draw(self):
        if not self.alive:
            self.window.close()
            n = Viewer.instances.index(self)
            del Viewer.instances[n]
        else:
            self._on_draw()

        symbol = self.last_key_pressed
        if symbol is not None:
            self.last_key_pressed = None
            return symbol
        return None

    @classmethod
    def draw_all(cls):
        """Draw all changes for all viewers to screen."""

        key_pressed = None, None
        for viewer in Viewer.instances:
            symbol = viewer.draw()
            if symbol is not None:
                key_pressed = symbol, viewer
        return key_pressed

    def set_callback(self, key, callback, global_event=False, modifier=None):
        if modifier is not None:
            raise Exception("not implemented") #XXX
        if global_event:
            Viewer.key_events[key] = callback
        else:
            self.key_events[key] = callback

def preview(image, blocking=True, use_imshow=True):
    if use_imshow:
        if blocking:
            imshow(image)
        else:
            t = threading.Thread(target=lambda: imshow(image))
            t.start()
    else:
        viewer = Viewer()
        viewer.update_image(image, draw=True, copy=True)
        if blocking:
            while 1:
                viewer.draw()
                if not viewer.alive:
                    break
        else:
            def g():
                while 1:
                    viewer.draw()
                    if not viewer.alive:
                        break
                    time.sleep(0.1)
            threading.Thread(target=lambda: g)

def main():
    filename = "../media/traffic.avi"
    filename = "../media/test.mpg"
    #~ filename = "/misc/janto/images/activities_fall_janto/005_vlc.mp4"

    v = Viewer(show_fps=True)
    t = time.time()

    for frame in Video(filename).frames(do_change=False):

        im = frame["clean"]
        v.update_image(im)
        v.draw()
        if not v.alive:
            break

    print time.time() - t, "seconds"

if __name__ == "__main__":
    main()
